package com.mf.service.impl.upload;


import com.mf.config.MinIOConfig;
import com.mf.enums.EnumBasicResultCode;
import com.mf.service.upload.IFileUploadBusiness;
import com.mf.utils.MinIOUtils;
import io.github.heollhai.common.config.exceptions.GraceException;
import io.github.heollhai.common.config.reids.RedisOperator;
import io.minio.ComposeSource;
import io.minio.messages.DeleteObject;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;


/**
 * @Author: lmf
 * @Create: 2024/11/20 21:13
 * Description: 文件上传业务实现类
 */
@Slf4j
@Service
public class FileUploadBusinessImpl implements IFileUploadBusiness {


    @Resource
    private MinIOUtils minioUtils;

    @Resource
    private RedisOperator redisDao;

    @Resource
    private MinIOConfig minioConfig;


    /**
     * 完整文件上传
     */
    @Override
    public Boolean uploadFile(String bucketName, String objectName, MultipartFile file) {
        //  文件上传
        return minioUtils.uploadFile(bucketName, objectName, null, file);
    }

    /**
     * 把文件块上传到分片桶
     *
     * @return Integer 要上传的分片数，-1是上传完成
     */
    @Override
    public Integer uploadSliceFile(String fullMd5Name, Integer totalPieces, Integer sliceIndex,
                                   MultipartFile file) {
        // 分片上传完毕标志
        Integer isUploaded = -1;
        // 无需合并标志
        Integer isCompose = -2;
        // 获取当前需要上传的文件下标
        Object sliceIndexRedis = redisDao.indexValue(fullMd5Name, 0);
        String sliceIndexStr = String.valueOf(sliceIndexRedis);
        if (!"".equals(sliceIndexRedis) && null != sliceIndexRedis) {
            Integer sliceIndexRedisInt = Integer.parseInt(sliceIndexStr);
            // 索引不一致，要求一致
            if (!sliceIndexRedisInt.equals(sliceIndex)) {
                GraceException.display(EnumBasicResultCode.UPLOAD_INDEX_UNMATCHED);
                //Result.(Constants.ResponseCode.UPLOAD_INDEX_UNMATCHED.getCode(),
                // Constants.ResponseCode.UPLOAD_INDEX_UNMATCHED.getMsg(), sliceIndexRedisInt);
            }
        } else {
            log.debug("缓存中无此分片信息，可能已经全部上传完毕，或没有初始化分片");
            // 无分片，可能上传完了，所以不需要合并
            return isCompose;
        }
        // 上传分片文件
        Boolean isUpload = minioUtils.uploadFile(minioConfig.getBucketNameSlice(), fullMd5Name, sliceIndex, file);
        if (!isUpload) {
            // 上传失败
//        return Result.failed(Constants.ResponseCode.UPLOAD_FILE_FAILED.getCode(),
//                Constants.ResponseCode.UPLOAD_FILE_FAILED.getMsg(), sliceIndex);
            GraceException.display(EnumBasicResultCode.UPLOAD_FILE_FAILED);

        }
        // 上传完成删除缓存中的分片
        // TODO 删除判断
        boolean isRemove = redisDao.remove(fullMd5Name, sliceIndexStr, 1);
        if (sliceIndex < totalPieces - 1) {
            return sliceIndex + 1;
        }
        return isUploaded;

    }

    /**
     * 分片合并
     *
     * @return Boolean ture成功，false是失败
     */
    @Override
    public Boolean composeFile(String bucketName, String fullObjectName, Integer totalPieces) {
        // 完成上传从缓存目录合并迁移到正式目录
        List<ComposeSource> sourceObjectList = Stream.iterate(0, i -> ++i)
                .limit(totalPieces)
                .map(i -> ComposeSource.builder()
                        .bucket(minioConfig.getBucketNameSlice())
                        .object(fullObjectName.concat("/").concat(Integer.toString(i)))
                        .build())
                .collect(Collectors.toList());
        log.debug("文件合并|composeFile|,fullObjectName:{},totalPieces:{}", fullObjectName, totalPieces);
        // 合并操作
        return minioUtils.composeFile(bucketName, fullObjectName, sourceObjectList);
    }


    /**
     * 删除minio分片文件
     *
     * @return Boolean ture成功，false是失败
     */
    @Override
    public Boolean delSliceFile(String objectName, Integer totalPieces) {
        // 删除所有的临时分片文件
        List<DeleteObject> delObjects = Stream.iterate(0, i -> ++i)
                .limit(totalPieces)
                .map(i -> new DeleteObject(objectName.concat("/").concat(Integer.toString(i))))
                .collect(Collectors.toList());
        return minioUtils.removeFiles(minioConfig.getBucketNameSlice(), delObjects);
    }

    /**
     * 初始化时创建桶
     *
     * @return Boolean ture成功，false是失败
     */
    @Override
    public Boolean createFileBucket(String bucketName) {
        boolean sliceBucket = minioUtils.createBucket(minioConfig.getBucketNameSlice());
        boolean fileBucket = minioUtils.createBucket(bucketName);
        return sliceBucket && fileBucket;
    }

    /**
     * 初始化时创建分片桶
     */
    @Override
    public Boolean sliceInRedis(String fullMd5Name, Integer totalSlice) {
        if (!redisDao.keyIsExist(fullMd5Name)) {
            for (int i = 0; i < totalSlice; i++) {
                redisDao.rPush(fullMd5Name, String.valueOf(i));
            }
        }
        return true;
    }

}
